<!DOCTYPE html>

<html>

<head>
  <title>Example 05 - uniform</title>
  <script type="text/javascript" src="../three/build/three.js"></script>
  <script type="text/javascript" src="../three/examples/js/controls/OrbitControls.js"></script>
  <script type="text/javascript" src="../three/examples/js/loaders/OBJLoader.js"></script>
  <script type="text/javascript" src="../three/examples/js/libs/stats.min.js"></script>
  <!-- EffectComposer要先于其他后期处理文件引入，否则其他文件无法正确引入 -->
  <script type="text/javascript" src="../three/examples/js/postprocessing/EffectComposer.js"></script>
  <script type="text/javascript" src="../three/examples/js/postprocessing/RenderPass.js"></script>
  <script type="text/javascript" src="../three/examples/js/postprocessing/ShaderPass.js"></script>
  <script type="text/javascript" src="../three/examples/js/shaders/CopyShader.js"></script>


  <style>
    body {
      margin: 0;
      overflow: hidden;
    }
  </style>
</head>

<body>

  <div id="Stats-output"></div>
  <div id="WebGL-output"></div>

  <script type="text/javascript">
    let stats, controls, composer, customPass;
    let camera, scene, renderer;
    let boxMaterialShader = {
      uniforms: {
        "r": {
          type: "f",
          value: 1.0
        },
        "g": {
          type: "f",
          value: 0.6
        },
        "b": {
          type: "f",
          value: 0.8
        }
      },
      vertexShader: `
      void main(){
        gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
      }
    `,
      fragmentShader: `
      uniform float r;
      uniform float g;
      uniform float b;
      void main(){
        gl_FragColor = vec4(vec3(r,g,b),0.9);
      }
    `
    };

    //创建ShaderMaterial材质
    const material = new THREE.ShaderMaterial({
      uniforms: boxMaterialShader.uniforms,
      vertexShader: boxMaterialShader.vertexShader,
      fragmentShader: boxMaterialShader.fragmentShader,
      side: THREE.DoubleSide
    })
    material.needsUpdate = true

    function initScene() {
      scene = new THREE.Scene();
    }

    function initCamera() {
      camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
      camera.position.set(30, 80, 80)
      camera.lookAt(new THREE.Vector3(0, 0, 0));
    }

    function initLight() {
      //添加环境光
      var ambientLight = new THREE.AmbientLight(0xffffff);
      scene.add(ambientLight);

      var spotLight = new THREE.SpotLight(0xffffff);
      spotLight.position.set(5, 10, 20);
      spotLight.castShadow = true;
      scene.add(spotLight);
    }


    function initModel() {

      //创建BufferGeometry几何体
      const bufferGeom = new THREE.BufferGeometry()

      //设置顶点信息
      const positions = new Float32Array([
        -5.0, 2.0, -5.0,
        5.0, 2.0, -5.0,
        5.0, 2.0, 5.0,
        -5.0, 2.0, 5.0,
        -6.0, -2.0, -6.0,
        6.0, -2.0, -6.0,
        6.0, -2.0, 6.0,
        -6.0, -2.0, 6.0,
      ])
      bufferGeom.setAttribute('position', new THREE.BufferAttribute(positions, 3))

      //设置索引信息
      const indexs = new Uint16Array([
        0, 1, 2, //上
        0, 2, 3, //上
        4, 5, 6, //下
        4, 6, 7, //下
        0, 3, 4, //左
        3, 4, 7, //左
        1, 2, 5, //右
        2, 5, 6, //右
        2, 3, 6, //前
        3, 6, 7, //前
        0, 1, 4, //后
        1, 4, 5, //后
      ])
      bufferGeom.index = new THREE.BufferAttribute(indexs, 1)

      //创建Mesh对象并添加到场景
      const mesh = new THREE.Mesh(bufferGeom, material)
      scene.add(mesh)



      // 绘制边框
      const lineGeom = bufferGeom.clone() //克隆一份BufferGeometry对象

      //设置绘制线的索引
      const lineIndexs = new Uint16Array([
        0, 1, 1, 2, 2, 3, 3, 0,
        4, 5, 5, 6, 6, 7, 7, 4,
        0, 4, 1, 5, 2, 6, 3, 7
      ])
      lineGeom.index = new THREE.BufferAttribute(lineIndexs, 1)

      //创建绘制线的材质
      const lineMaterial = new THREE.LineBasicMaterial({
        color: 0x018BF5,
        side: THREE.DoubleSide
      })

      //使用LineSegments绘制线段，渲染时mode为gl.LINES
      const line = new THREE.LineSegments(lineGeom, lineMaterial)
      scene.add(line)

    }

    function initRender() {

      renderer = new THREE.WebGLRenderer({
        antialias: true,
        alpha: true
      })
      //renderer.shadowMap.enabled = true // 显示阴影
      renderer.setPixelRatio(window.devicePixelRatio);
      renderer.setSize(window.innerWidth, window.innerHeight);
      renderer.setClearColor(0x0f2d48, 1) // 设置背景颜色
      renderer.toneMapping = THREE.ACESFilmicToneMapping;
      document.getElementById("WebGL-output").appendChild(renderer.domElement);
    }

    //初始化轨道控制器
    function initControls() {
      clock = new THREE.Clock() // 创建THREE.Clock对象，用于计算上次调用经过的时间
      controls = new THREE.OrbitControls(camera, renderer.domElement)
      //controls.autoRotate = true // 是否自动旋转
    }



    function init() {
      initScene();
      initCamera();
      initLight();
      initRender();
      initStats();
      initControls();
      initModel();
      render();
    }



    function updateFun() {
      stats.update();
      const delta = clock.getDelta() // 获取自上次调用的时间差
      controls.update(delta) // 相机更新

      //更新传给着色器材质的uniform变量
      boxMaterialShader.uniforms.r.value += 0.01
      boxMaterialShader.uniforms.g.value += 0.01
      if (boxMaterialShader.uniforms.r.value > 1) {
        boxMaterialShader.uniforms.r.value = 0.1
      }
      if (boxMaterialShader.uniforms.g.value > 1) {
        boxMaterialShader.uniforms.g.value = 0.1
      }

    }

    function render() {
      updateFun()
      requestAnimationFrame(render);
      renderer.render(scene, camera);
    }

    function initStats() {
      stats = new Stats();
      stats.setMode(0); // 0: fps, 1: ms

      document.getElementById("Stats-output").appendChild(stats.domElement);
    }

    window.onload = init;
  </script>
</body>

</html>